package com.skyvin.nreceipts.receipts.service;

import java.util.List;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.skyvin.nreceipts.admin.service.ReceiptCategoryService;
import com.skyvin.nreceipts.admin.service.ReceiptItemCategoryService;
import com.skyvin.nreceipts.admin.service.RetailerService;
import com.skyvin.nreceipts.common.document.Receipt;
import com.skyvin.nreceipts.common.document.ReceiptCategory;
import com.skyvin.nreceipts.common.document.ReceiptItem;
import com.skyvin.nreceipts.common.document.ReceiptItemCategory;
import com.skyvin.nreceipts.common.document.ReceiptUpload;
import com.skyvin.nreceipts.common.document.Retailer;
import com.skyvin.nreceipts.common.exception.NReceiptsRunTimeException;
import com.skyvin.nreceipts.common.service.BaseService;
import com.skyvin.nreceipts.receipts.mongorepository.ReceiptRepository;
import com.skyvin.nreceipts.user.mongorepository.AppUserRepository;
import com.skyvin.nreceipts.user.service.UserService;

@Service
public class ReceiptService extends BaseService {
	private Logger logger = Logger.getLogger(ReceiptService.class);
	public static String NO_RECEIPTHEADER_FOUND_MESSAGE = "Please save Receipt header information before saving item";

	@Autowired
	ReceiptRepository receiptRepository;
	// @Autowired
	// ReceiptItemRepository receiptItemRepository;
	@Autowired
	AppUserRepository appUserRepository;
	@Autowired
	RetailerService retailerService;
	@Autowired
	ReceiptUploadService receiptUploadService;
	@Autowired
	ReceiptCategoryService receiptCategoryService;
	@Autowired
	ReceiptItemCategoryService receiptItemCategoryService;

	@Autowired
	UserService userService;

	@Autowired
	MongoTemplate mongoTemplate;

	/**
	 * This method does the following - Creates the Retailer if it does not
	 * exist. - Creates the Receipt Category if it does not exist.
	 * 
	 * @param receipt
	 */
	@Transactional
	public Receipt saveReceiptHeader(Receipt receipt) {
		logger.info("receipt.getRetailer().getId() : " + receipt.getRetailer().getId());
		ReceiptUpload receiptUpload = null;
		String userPID = receipt.getUserPID();

		Retailer retailer = createRetailerIfNotExists(receipt.getRetailer(), userPID);
		receipt.setRetailer(retailer);

		ReceiptCategory receiptCategory = createReceiptCategoryIfNotFound(receipt.getReceiptCategory(), userPID);
		receipt.setReceiptCategory(receiptCategory);

		// --- Receipt Upload
		ReceiptUpload receiptUploadPassed = receipt.getReceiptUpload();
		if (receiptUploadPassed != null) {
			String receiptUploadID = receipt.getReceiptUpload().getId();
			receiptUpload = receiptUploadService.getMyReceiptUpload(receiptUploadID);
			receipt.setReceiptUpload(receiptUpload);
		}

		receiptRepository.save(receipt);

		mongoTemplate.save(receipt, getMyCollection(Receipt.class));
		Receipt myReceiptCreated = mongoTemplate
				.findOne(new Query(Criteria.where("name").is(receipt.getName())), Receipt.class, getMyCollection(Receipt.class));
		logger.info("ID Generated : " + myReceiptCreated.getId());
		return myReceiptCreated;

	}

	@Transactional
	public void saveReceiptItem(ReceiptItem receiptItem) {
		ReceiptItemCategory receiptItemCategory = null;
		String userPID = receiptItem.getUserPID();
		Receipt receiptHeader = receiptItem.getReceipt();
		if (receiptHeader == null || receiptHeader.getId() == null || receiptHeader.getId().equals("")) {
			throw new NReceiptsRunTimeException("ReceiptService:saveReceiptItem", NO_RECEIPTHEADER_FOUND_MESSAGE, NO_RECEIPTHEADER_FOUND_MESSAGE, null);
		} else {
			// Creating item category if not found already...
			receiptItemCategory = createReceiptItemCategoryIfNotFound(receiptItem.getReceiptItemCategory(), userPID);
			receiptItem.setReceiptItemCategory(receiptItemCategory);
			receiptItem.setId(UUID.randomUUID().toString());

			DBObject dbo = new BasicDBObject();
			mongoTemplate.getConverter().write(receiptItem, dbo);

			// Adding receipt item to the receipt...
			Query query = new Query(Criteria.where("id").is(receiptHeader.getId()));
			mongoTemplate.updateFirst(query, new Update().push("receiptItems", dbo), getMyCollection(Receipt.class));
			mongoTemplate.updateFirst(query, new Update().push("receiptItems", dbo), Receipt.class);

		}
	}

	/**
	 * This method creates the retailer if it is not found in the db, else it
	 * gets the reference from the db and returns it back
	 * 
	 * @param receiptItemCategoryPassedByUser
	 * @param userPID
	 * @return
	 */
	private ReceiptItemCategory createReceiptItemCategoryIfNotFound(ReceiptItemCategory receiptItemCategoryPassedByUser, String userPID) {
		ReceiptItemCategory receiptItemCategory = receiptItemCategoryService.getMyReceiptItemCategoryByName(receiptItemCategoryPassedByUser.getValue());
		if (receiptItemCategory == null) {
			receiptItemCategoryPassedByUser.setUserPID(userPID);
			receiptItemCategory = receiptItemCategoryService.save(receiptItemCategoryPassedByUser);
		}
		return receiptItemCategory;
	}

	/**
	 * This method creates the retailer if it is not found in the db, else it
	 * gets the reference from the db and returns it back
	 * 
	 * @param retailerPassedByUser
	 * @param userPID
	 * @return
	 */
	private Retailer createRetailerIfNotExists(Retailer retailerPassedByUser, String userPID) {
		// Get the reference of the retailer
		Retailer retailer = retailerService.getMyRetailerByName(retailerPassedByUser.getValue());
		if (retailer == null) {
			retailerPassedByUser.setUserPID(userPID);
			// if retailer does not exist
			retailer = retailerService.save(retailerPassedByUser);
		}
		return retailer;
	}

	/**
	 * This method creates the receipt category if it is not found in the db,
	 * else it gets the reference from the db and returns it back
	 * 
	 * @param receiptCategoryPassed
	 * @param userPID
	 * @return
	 */
	private ReceiptCategory createReceiptCategoryIfNotFound(ReceiptCategory receiptCategoryPassed, String userPID) {

		// Get the reference of the retailer
		ReceiptCategory receiptCategory = receiptCategoryService.getMyReceiptCategoryByName(receiptCategoryPassed.getValue());
		if (receiptCategory == null) {

			receiptCategoryPassed.setUserPID(userPID);
			// if retailer does not exist
			receiptCategory = receiptCategoryService.save(receiptCategoryPassed);
		}
		return receiptCategory;
	}

	public void removeMyReceipt(String receiptID) {
		// receiptRepository.delete(receiptID);
		Query query = new Query(Criteria.where("id").is(receiptID));
		mongoTemplate.findAndRemove(query, Receipt.class, getMyCollection(Receipt.class));
	}

	public Receipt getMyReceipt(String id) {
		// return receiptRepository.findOne(id);
		Query query = new Query(Criteria.where("id").is(id));
		return mongoTemplate.findOne(query, Receipt.class, getMyCollection(Receipt.class));
	}

	public void deleteMyReceiptItem(String id) {
		// receiptItemRepository.delete(id);
		Query query = new Query(Criteria.where("id").is(id));
		mongoTemplate.findAndRemove(query, ReceiptItem.class, getMyCollection(ReceiptItem.class));

	}

	public ReceiptItem getMyReceiptItem(String id) {
		// TODO Auto-generated method stub
		// return receiptItemRepository.findOne(id);
		Query query = new Query(Criteria.where("id").is(id));
		return mongoTemplate.findOne(query, ReceiptItem.class, getMyCollection(ReceiptItem.class));
	}

	public List<ReceiptItem> getMyReceiptItems(String receiptID) {
		
		Query query = new Query(Criteria.where("id").is(receiptID));
		Receipt receipt = mongoTemplate.findOne(query, Receipt.class, getMyCollection(Receipt.class));
		return receipt.getReceiptItems();
	}

	public void deleteMyReceipt(String receiptPID) {
		Query query = new Query(Criteria.where("id").is(receiptPID));
		Receipt receipt = mongoTemplate.findOne(query, Receipt.class, getMyCollection(Receipt.class));
		List<ReceiptItem> receiptItems = receipt.getReceiptItems();
		ReceiptUpload receiptUpload = receipt.getReceiptUpload();

		// Delete Receipt Upload
		mongoTemplate.remove(receiptUpload, getMyCollection(ReceiptUpload.class));

		// Delete receipt Item
		for (ReceiptItem receiptItem : receiptItems) {
			mongoTemplate.remove(receiptItem, getMyCollection(ReceiptItem.class));
		}
		// Delete receipt
		mongoTemplate.remove(receipt, getMyCollection(Receipt.class));

		// Delete receipt image from the repository
		// TODO: Write logic to remove from the repository
	}

}
